#include <stdio.h>
#include <stdlib.h>

//增量式PID
typedef struct{
	int SetPoint;		//目标值
	long Sumoutor;		//误差累计
	
	float P;			//比例常数
	float I;			//积分常数
	float D;			//微分常数
	
	int lastoutor;		//上次偏差值
	int Prevoutor;		//上上次偏差值
}PID;
 
/*************************************************
 *函数名称:void PID_Arg_Init(PID* sptr)                              
 *功    能:参数初始化                                     
 *参    数:PID* sptr                                     
 *返 回 值:void                                       
 *************************************************/
void PID_Arg_Init(PID* sptr)
{
	sptr->Sumoutor = 0;         //误差累计 
	sptr->lastoutor = 0;        //上次偏差值
	sptr->Prevoutor = 0;        //上上次偏差值
	                            
	sptr->P = 0;                //比例常数
	sptr->I = 0;                //积分常数
	sptr->D = 0;                //微分常数
	                            
	sptr->SetPoint = 0;			//目标值
}
/*************************************************
 *函数名称:int PID_Contrl(PID* sptr,int NextPoint)                             
 *功    能:PID控制                                   
 *参    数:PID* sptr：上次参数  int NextPoint：当前实际值                                   
 *返 回 值:void                                       
 *************************************************/
int PID_Contrl(PID* sptr,int NextPoint)
{
	int ioutor,iIncPid;
	ioutor = sptr->SetPoint - NextPoint;	//当前误差  设定的目标值和实际值的偏差
	
	iIncPid = sptr->P * ioutor				//增量计算
			  - sptr->I * sptr->lastoutor
			  + sptr->D * sptr->Prevoutor;
	
	/*存储误差  用于下次计算*/
	sptr->Prevoutor = sptr->lastoutor;
	sptr->lastoutor = ioutor;
	
	return iIncPid;							//返回增量值
}
 
int main()
{
	FILE *fp;
	int err = 0;
	int out = 0;
	int in =80;
	int i = 0;

	int cnt = 0;
 
	PID pid;
	PID_Arg_Init(&pid);
	pid.SetPoint = 3000;
	pid.P = 0.6;
	pid.I= 0.3;
	pid.D = 0.2;

	if( (fp = fopen("m.dat", "w")) == NULL){
		printf("File open error!\r\n");
		exit(1);
	}

	for( i = 0;i < 300;i++)
	{
		err = PID_Contrl(&pid,in);
		out += err;
		fprintf(fp,"%d %d %d\n",i,out, pid.SetPoint);
		//printf("%d %d\n",out,pid.SetPoint);	
		in = out + rand()%10;

			cnt++;
			if( abs(in-pid.SetPoint) < 10){
				in = out + rand()%12-6;
			} else if(pid.SetPoint -in > 20 ){
				in = in + (2*pid.SetPoint / (rand()/233) );
			} else if(in - pid.SetPoint > 10){
				in = in - rand()%3;
			}

		printf("%d\n",rand()%20-10);
		
	}

	if(fclose(fp)){
		printf("Can not close the file!\n");
		exit(1);
	}
   return 0;
}